home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2.sit / Raven 1.2 / Source / Foundation / OS / ZCursor.cpp < prev    next >
Text File  |  1997-06-18  |  20KB  |  812 lines

  1. /*
  2.  *  File:       ZCursor.cpp
  3.  *  Summary:    Mouse cursor classes.
  4.  *  Written by: Jesse Jones
  5.  *
  6.  *  Copyright ゥ 1996-1997 Jesse Jones. 
  7.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  8.  *
  9.  *  Change History (most recent first):    
  10.  *
  11.  *         <2>     3/30/97    JDJ        StillBusy only tickles the cursor if more than
  12.  *                                    a tick has elapsed since the last tickle.
  13.  *         <1>     2/24/96    JDJ        Created.
  14.  */
  15.  
  16. #include <ZCursor.h>
  17.  
  18. #include <CursorDevices.h>    
  19. #include <LowMem.h>
  20. #include <ToolUtils.h>
  21. #include <Traps.h>
  22.  
  23. #include <SLFunctions.h>
  24. #include <ZDebug.h>
  25. #include <ZExceptions.h>
  26. #include <ZGestalt.h>
  27. #include <ZInterruptTimer.h>
  28.  
  29.  
  30. //-----------------------------------
  31. //    Constants
  32. //
  33. const ResID kArrowID     = 0;
  34. const ResID kIBeamID     = 1;
  35. const ResID kCrossHairID = 2;
  36. const ResID kPlusID      = 3;
  37. const ResID kWatchID     = 4;
  38.  
  39. const ResID kOpenHandID   = 128;
  40. const ResID kClosedHandID = 134;
  41. const ResID kEyeDropperID = 129;
  42. const ResID kBrushID      = 130;
  43. const ResID kPencilID     = 131;
  44.  
  45. const ResID kSpinningWatchID = 210;
  46. const ResID kBeachBallID     = 200;
  47. const ResID kEmptyArrowID    = 220;
  48.  
  49.  
  50. // ・・・ The glue code in InterfaceLib for the Cursor Devices manager is 
  51. // ・・・ハincorrect for PPC builds. Until this is fixed we'll use our
  52. // ・・・ own glue code.
  53. #ifndef HAS_WORKING_CURSOR_DEVICES
  54. #define HAS_WORKING_CURSOR_DEVICES    (!powerc)
  55. #endif
  56.  
  57. #if !HAS_WORKING_CURSOR_DEVICES
  58. enum {        
  59.     uppCursorDeviceNextDeviceProcInfo = 
  60.         kD0DispatchedPascalStackBased | 
  61.         RESULT_SIZE(kTwoByteCode) |
  62.         STACK_ROUTINE_PARAMETER(1, kTwoByteCode)  |
  63.         STACK_ROUTINE_PARAMETER(2, kFourByteCode),
  64.         
  65.     uppCursorDeviceMoveProcInfo = 
  66.         kD0DispatchedPascalStackBased | 
  67.         RESULT_SIZE(kTwoByteCode) |
  68.         STACK_ROUTINE_PARAMETER(1, kTwoByteCode)  |
  69.         STACK_ROUTINE_PARAMETER(2, kFourByteCode) |
  70.         STACK_ROUTINE_PARAMETER(3, kFourByteCode) |
  71.         STACK_ROUTINE_PARAMETER(4, kFourByteCode),
  72.         
  73.     uppCursorDeviceMoveToProcInfo = 
  74.         kD0DispatchedPascalStackBased | 
  75.         RESULT_SIZE(kTwoByteCode) |
  76.         STACK_ROUTINE_PARAMETER(1, kTwoByteCode)  |
  77.         STACK_ROUTINE_PARAMETER(2, kFourByteCode) |
  78.         STACK_ROUTINE_PARAMETER(3, kFourByteCode) |
  79.         STACK_ROUTINE_PARAMETER(4, kFourByteCode)
  80. };
  81. #endif
  82.  
  83.  
  84. // ===================================================================================
  85. //    Helper Functions
  86. // ===================================================================================
  87.  
  88. //---------------------------------------------------------------
  89. //
  90. //    MyCursorDeviceNextDevice
  91. //
  92. //---------------------------------------------------------------
  93. static OSErr MyCursorDeviceNextDevice(CursorDevicePtr *ourDevice)
  94. {
  95. #if HAS_WORKING_CURSOR_DEVICES
  96.     return CursorDeviceNextDevice(ourDevice);
  97. #else
  98.     UniversalProcPtr trap = NGetTrapAddress(_CursorDeviceDispatch, ToolTrap);
  99.     return (OSErr) CallUniversalProc(trap, uppCursorDeviceNextDeviceProcInfo, 0x0B, ourDevice);    
  100. #endif
  101. }
  102.  
  103.  
  104. //---------------------------------------------------------------
  105. //
  106. //    MyCursorDeviceMove
  107. //
  108. //---------------------------------------------------------------
  109. static OSErr MyCursorDeviceMove(CursorDevicePtr ourDevice, long deltaX, long deltaY)
  110. {
  111. #if HAS_WORKING_CURSOR_DEVICES
  112.     return CursorDeviceMove(ourDevice, deltaX, deltaY);
  113. #else
  114.     UniversalProcPtr trap = NGetTrapAddress(_CursorDeviceDispatch, ToolTrap);
  115.     return (OSErr) CallUniversalProc(trap, uppCursorDeviceMoveProcInfo, 0x00, ourDevice, deltaX, deltaY);
  116. #endif
  117. }
  118.  
  119.  
  120. //---------------------------------------------------------------
  121. //
  122. //    MyCursorDeviceMoveTo
  123. //
  124. //---------------------------------------------------------------
  125. static OSErr MyCursorDeviceMoveTo(CursorDevicePtr ourDevice, long deltaX, long deltaY)
  126. {
  127. #if HAS_WORKING_CURSOR_DEVICES
  128.     return CursorDeviceMoveTo(ourDevice, deltaX, deltaY);
  129. #else
  130.     UniversalProcPtr trap = NGetTrapAddress(_CursorDeviceDispatch, ToolTrap);
  131.     return (OSErr) CallUniversalProc(trap, uppCursorDeviceMoveToProcInfo, 0x01, ourDevice, deltaX, deltaY);
  132. #endif
  133. }
  134.  
  135. #pragma mark -
  136.  
  137. // ===================================================================================
  138. //    class TCursor
  139. // ===================================================================================
  140. const TCursor kArrowCursor(kArrowID);
  141. const TCursor kIBeamCursor(kIBeamID);
  142. const TCursor kCrossHairCursor(kCrossHairID);
  143. const TCursor kPlusCursor(kPlusID);
  144. const TCursor kWatchCursor(kWatchID);
  145.  
  146. const TCursor kOpenHandCursor(kOpenHandID);            
  147. const TCursor kClosedHandCursor(kClosedHandID);            
  148. const TCursor kEyeDropperCursor(kEyeDropperID);
  149. const TCursor kBrushCursor(kBrushID);
  150. const TCursor kPencilCursor(kPencilID);
  151.  
  152. const TCursor kSpinningWatchCursor(kSpinningWatchID);
  153. const TCursor kBeachBallCursor(kBeachBallID);
  154. const TCursor kEmptyArrowCursor(kEmptyArrowID);
  155.  
  156.  
  157. //---------------------------------------------------------------
  158. //
  159. // TCursor::~TCursor
  160. //
  161. //---------------------------------------------------------------
  162. TCursor::~TCursor()
  163. {
  164.     if (mColorCursor != nil)
  165.         DisposeCCursor(mColorCursor);
  166.  
  167.     delete mBwCursor;
  168. }
  169.  
  170.  
  171. //---------------------------------------------------------------
  172. //
  173. // TCursor::TCursor (ResID)
  174. //
  175. //---------------------------------------------------------------
  176. TCursor::TCursor(ResID id)
  177. {
  178.     mColorCursor = nil;
  179.     mBwCursor = nil;
  180.     mID = id;
  181.  
  182.     SLDisable();                            // Spotlight will complain if there's no color cursor
  183.     mColorCursor = ::GetCCursor(mID);
  184.     SLEnable();
  185.  
  186.     if (mColorCursor == nil) {
  187.         mBwCursor = new Cursor;
  188.  
  189.         if (mID != 0) {
  190.             CursHandle cursor = GetCursor(mID);
  191.             ThrowIfResFail(cursor);
  192.     
  193.             *mBwCursor = **cursor;
  194.     
  195.             HPurge((Handle) cursor);
  196.             
  197.         } else
  198.             *mBwCursor = qd.arrow;
  199.     }
  200. }
  201.  
  202.  
  203. //---------------------------------------------------------------
  204. //
  205. // TCursor::TCursor (TCursor)
  206. //
  207. //---------------------------------------------------------------
  208. TCursor::TCursor(const TCursor& rhs)
  209. {
  210.     mColorCursor = nil;
  211.     mBwCursor = nil;
  212.     mID = rhs.mID;
  213.  
  214.     if (rhs.mColorCursor != nil) {
  215.         mColorCursor = ::GetCCursor(rhs.mID);
  216.         ThrowIfResFail(mColorCursor);
  217.     }
  218.  
  219.     if (rhs.mBwCursor != nil) 
  220.         mBwCursor = new Cursor(*rhs.mBwCursor);
  221. }
  222.  
  223.  
  224. //---------------------------------------------------------------
  225. //
  226. // TCursor::operator=
  227. //
  228. //---------------------------------------------------------------
  229. TCursor& TCursor::operator=(const TCursor& rhs)
  230. {
  231.     if (this != &rhs && *this != rhs) {
  232.         CCrsrHandle colorCursor = nil;
  233.         Cursor*        bwCursor = nil;
  234.  
  235.         try {
  236.             if (rhs.mColorCursor != nil) {
  237.                 colorCursor = ::GetCCursor(rhs.mID);
  238.                 ThrowIfResFail(colorCursor);
  239.             }
  240.  
  241.             if (rhs.mBwCursor != nil) 
  242.                 bwCursor = new Cursor(*rhs.mBwCursor);
  243.  
  244.             if (mColorCursor != nil)
  245.                 DisposeCCursor(mColorCursor);
  246.             delete mBwCursor;
  247.  
  248.             mColorCursor = colorCursor;
  249.             mBwCursor = bwCursor;
  250.             mID = rhs.mID;
  251.  
  252.         } catch(...) {
  253.             if (colorCursor != nil)
  254.                 DisposeCCursor(colorCursor);
  255.  
  256.             delete bwCursor;
  257.  
  258.             throw;
  259.         }
  260.     }
  261.  
  262.     return *this;
  263. }
  264.  
  265. #pragma mark -
  266.  
  267. // ===================================================================================
  268. //    class ZCursorSpinner
  269. // ===================================================================================
  270. const MilliSecond kSpinFreq = 60;        
  271.  
  272. class ZCursorSpinner : public MTimeMgrTimer {
  273.  
  274.     typedef MTimeMgrTimer Inherited;
  275.  
  276. public:
  277.     virtual             ~ZCursorSpinner();
  278.  
  279.                         ZCursorSpinner(ResID id, MilliSecond timeOut);
  280.  
  281.     virtual void         StartTimer();
  282.                         
  283.             void         SetCursor(ResID newID);
  284.  
  285.             void         SetTimeout(MilliSecond timeOut);
  286.  
  287.             MilliSecond GetTimeout() const            {return (long) (1000*mDuration/60);}
  288.  
  289. protected:
  290.     virtual void         OnTime();
  291.  
  292. private:
  293.     ResID        mID;
  294.     Cursor*        mCursors;
  295.     short        mIndex;
  296.     short        mNoCursors;
  297.  
  298.     ulong        mStartTime;            // times are in ticks
  299.     ulong        mDuration;
  300. };
  301.  
  302.  
  303. //---------------------------------------------------------------
  304. //
  305. // ZCursorSpinner::~ZCursorSpinner
  306. //
  307. //---------------------------------------------------------------
  308. ZCursorSpinner::~ZCursorSpinner()
  309. {
  310.     this->StopTimer();                    // Don't want VBL task running while we tear down the object!
  311.  
  312.     delete [] mCursors;
  313. }
  314.  
  315.  
  316. //---------------------------------------------------------------
  317. //
  318. // ZCursorSpinner::ZCursorSpinner
  319. //
  320. //---------------------------------------------------------------
  321. ZCursorSpinner::ZCursorSpinner(ResID id, MilliSecond timeOut) : MTimeMgrTimer(kSpinFreq, false)
  322. {
  323.     ASSERT(id >= 128 && id < 32767);
  324.  
  325.     mCursors = nil;
  326.  
  327.     mIndex = 0;
  328.     mNoCursors = 0;
  329.     mID = 0;
  330.  
  331.     this->SetTimeout(timeOut);
  332.     this->SetCursor(id);
  333. }
  334.  
  335.  
  336. //---------------------------------------------------------------
  337. //
  338. // ZCursorSpinner::StartTimer
  339. //
  340. //---------------------------------------------------------------
  341. void ZCursorSpinner::StartTimer()
  342. {
  343.     if (mCursors != nil && mNoCursors > 0) {
  344.         ASSERT(mIndex >= 0 && mIndex < mNoCursors);
  345.         
  346.         ::SetCursor(&mCursors[mIndex]);
  347.     }
  348.  
  349.     mStartTime = (ulong) LMGetTicks();
  350.  
  351.     Inherited::StartTimer();
  352. }
  353.  
  354.  
  355. //---------------------------------------------------------------
  356. //
  357. // 'acur' struct
  358. //
  359. //---------------------------------------------------------------
  360. #if defined(powerc) || defined(__powerc)
  361. #pragma options align=mac68k
  362. #endif
  363.  
  364. struct SAcurEntry {
  365.     short    cursorID;
  366.     short    filler;
  367. };
  368.  
  369. struct SAcurRecord {
  370.     short        count;
  371.     short        filler;
  372.  
  373.     SAcurEntry    cursors[1];            // variable length array
  374. };
  375.  
  376. #if defined(powerc) || defined(__powerc)
  377. #pragma options align=reset
  378. #endif
  379.  
  380. typedef SAcurRecord*     AcurRecordPtr;
  381. typedef AcurRecordPtr*    AcurRecordHandle;
  382.  
  383.  
  384. //---------------------------------------------------------------
  385. //
  386. // ZCursorSpinner::SetCursor
  387. //
  388. //---------------------------------------------------------------
  389. void ZCursorSpinner::SetCursor(ResID newID)
  390. {
  391.     ASSERT(newID >= 128 && newID < 32767);
  392.  
  393.     if (mID != newID) {
  394.         AcurRecordHandle    acurRsrc = nil;
  395.         Cursor*             newCursors = nil;
  396.         bool                wasRunning = this->TimerIsRunning();
  397.  
  398.         try {
  399.             this->StopTimer();
  400.             
  401.             acurRsrc = (AcurRecordHandle) GetResource('acur', newID);
  402.             ThrowIfResFail(acurRsrc);
  403.  
  404.             HNoPurge((Handle) acurRsrc);
  405.             ThrowIfMemError();
  406.             
  407.             short count = (**acurRsrc).count;
  408.             newCursors = new Cursor[count];
  409.  
  410.             for (short index = 0; index < count; index++) {
  411.                 ResID cursorID = (**acurRsrc).cursors[index].cursorID;
  412.  
  413.                 CursHandle cursor = GetCursor(cursorID);
  414.                 ThrowIfResFail(cursor);
  415.                 
  416.                 LoadResource((Handle) cursor);
  417.  
  418.                 newCursors[index] = **cursor;
  419.  
  420.                 HPurge((Handle) cursor);
  421.             }
  422.  
  423.             mIndex = 0;
  424.             mNoCursors = count;
  425.  
  426.             delete [] mCursors;
  427.             mCursors = newCursors;
  428.  
  429.             HPurge((Handle) acurRsrc);
  430.             
  431.             if (wasRunning)
  432.                 this->StartTimer();
  433.  
  434.         } catch (...) {
  435.             DEBUGSTR("Couldn't initialize the spinning cursor!");
  436.  
  437.             delete [] newCursors;
  438.  
  439.             if (acurRsrc != nil)
  440.                 HPurge((Handle) acurRsrc);
  441.  
  442.             // Don't rethrow
  443.         }
  444.     }
  445. }
  446.  
  447.  
  448. //---------------------------------------------------------------
  449. //
  450. // ZCursorSpinner::SetTimeout
  451. //
  452. //---------------------------------------------------------------
  453. void ZCursorSpinner::SetTimeout(MilliSecond timeOut)
  454. {
  455.     mDuration = (ulong) (60*timeOut/1000);
  456. }
  457.  
  458.  
  459. //---------------------------------------------------------------
  460. //
  461. // ZCursorSpinner::OnTime
  462. //
  463. //---------------------------------------------------------------
  464. #pragma profile off
  465. void ZCursorSpinner::OnTime()        // interrupt code
  466. {
  467.     SAFE_ASSERT(mTimerFreq > 20);
  468.         
  469.     if (mCursors != nil && mNoCursors > 0) {
  470.         if (LMGetTicks() <= mStartTime + mDuration) {
  471.             if (!LMGetCrsrBusy()) {
  472.                 mIndex = (short) ((mIndex + 1) % mNoCursors);
  473.  
  474.                 SAFE_ASSERT(mIndex >= 0);
  475.                 SAFE_ASSERT(mIndex < mNoCursors);
  476.  
  477.                 ::SetCursor(&mCursors[mIndex]);
  478.             }
  479.         }
  480.     }
  481. }
  482. #pragma profile reset
  483.  
  484. #pragma mark -
  485.  
  486. // ===================================================================================
  487. //    class UCursorUtils
  488. // ===================================================================================
  489. const MilliSecond kDefaultTimeout = 10*1000;
  490.  
  491. TCursor    UCursorUtils::msBusyCursor(kSpinningWatchID);
  492.  
  493. TCursor    UCursorUtils::msCurrentCursor(kArrowID);
  494.  
  495. ZCursorSpinner* UCursorUtils::msCursorSpinner = nil;
  496.  
  497. CursorDevicePtr    UCursorUtils::msCursorDevice = nil;
  498.  
  499. bool UCursorUtils::msCanMoveMouse = false;
  500.  
  501.  
  502. //---------------------------------------------------------------
  503. //
  504. // UCursorUtils::Init
  505. //
  506. //---------------------------------------------------------------
  507. void UCursorUtils::Init()
  508. {
  509.     if (msCursorSpinner == nil) {
  510.     
  511.         // ZCursorSpinner does a lot of stuff that we don't want to
  512.         // do at static construction time so we'll create one the
  513.         // first time Init is called.
  514.         static ZCursorSpinner spinner(kSpinningWatchID, kDefaultTimeout);
  515.         msCursorSpinner = &spinner;
  516.  
  517.         // Rather than stuffing low mem globals we'll require that
  518.         // the Cursor Devices Manager is present for moving the mouse.
  519.         // (The CDM was introduced in Feb '93 and can be installed 
  520.         // on any Mac so this seems reasonable to do).
  521.         if (TrapAvailable(_CursorDeviceDispatch)) {
  522.         
  523.             // Get the first cursor device.
  524.             OSErr err = MyCursorDeviceNextDevice(&msCursorDevice);
  525.             if (err == noErr && msCursorDevice != nil) {
  526.             
  527.                 // Assume that we can move the mouse until we learn otherwise.
  528.                 msCanMoveMouse = true;
  529.  
  530.                 // Loop through all of the devices and see if any of them are 
  531.                 // absolute. If one of the devices is absolute disable mouse 
  532.                 // moving so weird things don't happen.
  533.                 CursorDevicePtr nextDevice = msCursorDevice;
  534.                 do {
  535.                     if (nextDevice->devClass == kDeviceClassAbsolute)
  536.                         msCanMoveMouse = false;
  537.                     err = MyCursorDeviceNextDevice(&nextDevice);
  538.                 } while (err == noErr && nextDevice != nil && msCanMoveMouse);
  539.             }        
  540.         
  541.         } else
  542.             msCanMoveMouse = false;
  543.     }
  544.     
  545.     // Stop spinning the busy cursor (we do this because it's legal
  546.     // to call Init at any time and we want to switch back to an arrow).
  547.     if (msCursorSpinner->TimerIsRunning())
  548.         msCursorSpinner->StopTimer();            
  549.  
  550.     // Switch the cursor to an arrow.
  551.     ::InitCursor();
  552.     if (msCurrentCursor.mID != kArrowID)
  553.         msCurrentCursor = TCursor(kArrowCursor);
  554. }
  555.  
  556.  
  557. //---------------------------------------------------------------
  558. //
  559. // UCursorUtils::SetCursor
  560. //
  561. //---------------------------------------------------------------
  562. void UCursorUtils::SetCursor(const TCursor& cursor)
  563. {
  564.     if (msCursorSpinner == nil)
  565.         UCursorUtils::Init();
  566.         
  567.     if (cursor == msBusyCursor)
  568.         UCursorUtils::ForceBusy();
  569.  
  570.     else {
  571.         msCursorSpinner->StopTimer();
  572.  
  573.         if (cursor.mColorCursor != nil)
  574.             ::SetCCursor(cursor.mColorCursor);
  575.         else
  576.             ::SetCursor(cursor.mBwCursor);
  577.     }
  578.  
  579.     if (msCurrentCursor != cursor)
  580.         msCurrentCursor = cursor;
  581. }
  582.  
  583.  
  584. //---------------------------------------------------------------
  585. //
  586. // UCursorUtils::ForceBusy ()
  587. //
  588. //---------------------------------------------------------------
  589. void UCursorUtils::ForceBusy()
  590. {
  591.     if (msCursorSpinner == nil)
  592.         UCursorUtils::Init();
  593.         
  594.     if (msCurrentCursor != msBusyCursor)
  595.         msCurrentCursor = msBusyCursor;
  596.  
  597.     msCursorSpinner->StartTimer();
  598. }
  599.  
  600.  
  601. //---------------------------------------------------------------
  602. //
  603. // UCursorUtils::ForceBusy (TCursor)
  604. //
  605. //---------------------------------------------------------------
  606. void UCursorUtils::ForceBusy(const TCursor& cursor)
  607. {
  608.     if (cursor != msBusyCursor)
  609.         UCursorUtils::InstallCustomBusyCursor(cursor);
  610.  
  611.     UCursorUtils::ForceBusy();
  612. }
  613.  
  614.  
  615. //---------------------------------------------------------------
  616. //
  617. // UCursorUtils::StillBusy
  618. //
  619. //---------------------------------------------------------------
  620. void UCursorUtils::StillBusy()
  621. {
  622.     if (msCursorSpinner == nil)
  623.         UCursorUtils::Init();
  624.         
  625.     static long lastTime = 0;            // this is often called in a tight loop so we'll only tickle the cursor if enough time elapses
  626.     
  627.     long time = (long) TickCount();
  628.         
  629.     if (msCurrentCursor == msBusyCursor && time != lastTime) {
  630.         msCursorSpinner->StartTimer();
  631.         
  632.         lastTime = time;
  633.     }
  634. }
  635.  
  636.  
  637. //---------------------------------------------------------------
  638. //
  639. // UCursorUtils::SetTimeout
  640. //
  641. //---------------------------------------------------------------
  642. void UCursorUtils::SetTimeout(MilliSecond duration)
  643. {
  644.     if (msCursorSpinner == nil)
  645.         UCursorUtils::Init();
  646.         
  647.     ASSERT(duration > 0);
  648.  
  649.     msCursorSpinner->SetTimeout(duration);
  650. }
  651.  
  652.  
  653. //---------------------------------------------------------------
  654. //
  655. // UCursorUtils::GetTimeout
  656. //
  657. //---------------------------------------------------------------
  658. MilliSecond UCursorUtils::GetTimeout()
  659. {
  660.     if (msCursorSpinner == nil)
  661.         UCursorUtils::Init();
  662.         
  663.     return msCursorSpinner->GetTimeout();
  664. }
  665.  
  666.  
  667. //---------------------------------------------------------------
  668. //
  669. // UCursorUtils::InstallCustomBusyCursor
  670. //
  671. //---------------------------------------------------------------
  672. void UCursorUtils::InstallCustomBusyCursor(const TCursor& newCursor)
  673. {
  674.     if (msCursorSpinner == nil)
  675.         UCursorUtils::Init();
  676.         
  677.     msBusyCursor = newCursor;
  678.  
  679.     msCursorSpinner->SetCursor(msBusyCursor.mID);
  680. }
  681.  
  682.  
  683. //---------------------------------------------------------------
  684. //
  685. // UCursorUtils::GetPosition
  686. //
  687. //---------------------------------------------------------------
  688. TPoint UCursorUtils::GetPosition()
  689. {
  690.     GrafPtr oldPort;
  691.     GetPort(&oldPort);
  692.     
  693.     GrafPtr windPort;
  694.     GetWMgrPort(&windPort);
  695.     SetPort(windPort);
  696.     
  697.     Point mouse;
  698.     GetMouse(&mouse);
  699.  
  700.     SetPort(oldPort);
  701.  
  702.     return mouse;
  703. }
  704.  
  705.  
  706. //---------------------------------------------------------------
  707. //
  708. // UCursorUtils::CanMove
  709. //
  710. //---------------------------------------------------------------
  711. bool UCursorUtils::CanMove()
  712. {
  713.     if (msCursorSpinner == nil)
  714.         UCursorUtils::Init();
  715.         
  716.     return msCanMoveMouse;
  717. }
  718.  
  719.  
  720. //---------------------------------------------------------------
  721. //
  722. // UCursorUtils::MoveTo
  723. //
  724. //---------------------------------------------------------------
  725. void UCursorUtils::MoveTo(short x, short y)
  726. {
  727.     VERIFY(UCursorUtils::CanMove());
  728.     
  729.     if (msCursorDevice != nil && msCanMoveMouse) {
  730.         OSErr err = MyCursorDeviceMoveTo(msCursorDevice, x, y);
  731.         ASSERT(err == noErr);
  732.  
  733.         long finalTicks;                        // Wait until the VBL task catches up with the new mouse position.
  734.         Delay(1, &finalTicks);
  735.     }
  736. }
  737.  
  738.  
  739. //---------------------------------------------------------------
  740. //
  741. // UCursorUtils::MoveBy
  742. //
  743. //---------------------------------------------------------------
  744. void UCursorUtils::MoveBy(short dx, short dy)
  745. {
  746.     VERIFY(UCursorUtils::CanMove());
  747.     
  748.     if (msCursorDevice != nil && msCanMoveMouse) {
  749.         OSErr err = MyCursorDeviceMove(msCursorDevice, dx, dy);
  750.         ASSERT(err == noErr);
  751.  
  752.         long finalTicks;                        // Wait until the VBL task catches up with the new mouse position.
  753.         Delay(1, &finalTicks);
  754.     }
  755. }
  756.  
  757. #pragma mark -
  758.  
  759. // ===================================================================================
  760. //    class TForceBusyCursor
  761. // ===================================================================================
  762.  
  763. //---------------------------------------------------------------
  764. //
  765. // TForceBusyCursor::~TForceBusyCursor
  766. //
  767. //---------------------------------------------------------------
  768. TForceBusyCursor::~TForceBusyCursor()
  769. {
  770.     if (mWasBusy)
  771.         if (mOldCursor == UCursorUtils::msBusyCursor)
  772.             UCursorUtils::ForceBusy();
  773.         else
  774.             UCursorUtils::ForceBusy(mOldCursor);
  775.             
  776.     else
  777.         UCursorUtils::SetCursor(mOldCursor);
  778. }
  779.  
  780.  
  781. //---------------------------------------------------------------
  782. //
  783. // TForceBusyCursor::TForceBusyCursor ()
  784. //
  785. //---------------------------------------------------------------
  786. TForceBusyCursor::TForceBusyCursor() : mOldCursor(UCursorUtils::msCurrentCursor)
  787. {
  788.     if (UCursorUtils::msCursorSpinner == nil)
  789.         UCursorUtils::Init();
  790.         
  791.     mWasBusy = UCursorUtils::msCursorSpinner->TimerIsRunning();
  792.         
  793.     UCursorUtils::ForceBusy();
  794. }
  795.  
  796.  
  797. //---------------------------------------------------------------
  798. //
  799. // TForceBusyCursor::TForceBusyCursor (TCursor)
  800. //
  801. //---------------------------------------------------------------
  802. TForceBusyCursor::TForceBusyCursor(const TCursor& cursor) : mOldCursor(UCursorUtils::msCurrentCursor)
  803. {
  804.     if (UCursorUtils::msCursorSpinner == nil)
  805.         UCursorUtils::Init();
  806.         
  807.     mWasBusy = UCursorUtils::msCursorSpinner->TimerIsRunning();
  808.         
  809.     UCursorUtils::ForceBusy(cursor);
  810. }
  811.  
  812.